package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.RabbitMQConfig;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.enums.CouponStateEnum;
import net.xdclass.enums.ProductOrderStateEnum;
import net.xdclass.enums.StockTaskStateEnum;
import net.xdclass.exception.BizException;
import net.xdclass.feign.ProductOrderFeignService;
import net.xdclass.mapper.ProductMapper;
import net.xdclass.mapper.ProductTaskMapper;
import net.xdclass.model.ProductDO;
import net.xdclass.model.ProductMessage;
import net.xdclass.model.ProductTaskDO;
import net.xdclass.request.LockProductRequest;
import net.xdclass.request.OrderItemRequest;
import net.xdclass.service.ProductService;
import net.xdclass.util.JsonData;
import net.xdclass.vo.ProductVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * @author : zhen.xue
 * @date : 2021-05-27 19:57
 */
@Service
@Slf4j
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductTaskMapper productTaskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private ProductOrderFeignService productOrderFeignService;

    @Override
    public Map<String, Object> page(int page, int size) {
        Page<ProductDO> pageInfo = new Page<>(page,size);
        Page<ProductDO> productDOPage = productMapper.selectPage(pageInfo, null);
        Map<String,Object> pageMap = new HashMap<>();
        pageMap.put("total_record",productDOPage.getTotal());
        pageMap.put("total_page",productDOPage.getPages());
        pageMap.put("current",productDOPage.getRecords().stream().map(this::beanProcess).collect(Collectors.toList()));
        return pageMap;
    }

    @Override
    public ProductVO findDetailById(long productId) {
        ProductDO productDO = productMapper.selectById(productId);
        return beanProcess(productDO);
    }

    @Override
    public List<ProductVO> findProductsByIdBatch(List<Long> productIdList) {
        List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList));
        List<ProductVO> productVOList = productDOList.stream().map(this::beanProcess).collect(Collectors.toList());
        return productVOList;
    }

    @Override
    public JsonData lockProductStock(LockProductRequest lockProductRequest) {
        List<OrderItemRequest> orderItemList = lockProductRequest.getOrderItemList();
        String orderOutTradeNo = lockProductRequest.getOrderOutTradeNo();
        //遍历商品锁定每个商品数量 ①
        List<Long> prodictIdList= orderItemList.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList());
        // 批量查询 ②
        List<ProductVO> productVOList = this.findProductsByIdBatch(prodictIdList);
        // 变成map ③
        Map<Long, ProductVO> productMap = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));
        //每次锁定都要发送延迟消息
        for (OrderItemRequest item : orderItemList) {
            int rows = productMapper.lockProductStock(item.getProductId(),item.getBuyNum());
            if (rows != 1){
                throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
            }else{
                // 插入商品的product_task ④
                ProductVO productVO = productMap.get(item.getProductId());
                ProductTaskDO productTaskDO = new ProductTaskDO();
                productTaskDO.setProductId(item.getProductId());
                productTaskDO.setBuyNum(item.getBuyNum());
                // ⑤ 如果不需要商品名称可以注释掉 ①  ②  ③ ④ ⑤
                productTaskDO.setProductName(productVO.getTitle() );
                productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
                productTaskDO.setOutTradeNo(orderOutTradeNo);
                productTaskDO.setCreateTime(new Date());
                productTaskMapper.insert(productTaskDO);
                log.info("商品库存锁定-插入商品product_task成功:{}",productTaskDO);
                //  发送MQ 延迟消息，解锁商品库存
                ProductMessage productMessage = new ProductMessage();
                productMessage.setOutTradeNo(orderOutTradeNo);
                // mybatispuls 自动返回id 这里面可以获取
                productMessage.setTaskID(productTaskDO.getId());
                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(),rabbitMQConfig.getStockReleaseDelayRoutingKey(),productMessage);
                log.info("商品库存锁定延迟消息发送成功:{}",productMessage);
            }
        }
        return JsonData.buildSuccess();
    }

    @Override
    public boolean releaseProductStock(ProductMessage productMessage) {
        ProductTaskDO productTaskDO = productTaskMapper.selectOne(new QueryWrapper<ProductTaskDO>().eq("id", productMessage.getTaskID()));
        if(productTaskDO == null){
            log.warn("工作单不存在，消息体为:{}",productMessage);
        }

        if(StockTaskStateEnum.LOCK.name().equalsIgnoreCase(productTaskDO.getLockState())){
            // 查询订单状态
            JsonData jsonData = productOrderFeignService.queryProductOrderState(productMessage.getOutTradeNo());
            if(0 == jsonData.getCode()){
                // 正常响应判断订单状态
                String state = jsonData.getData().toString();
                // 状态是 new 状态
                if(ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)){
                    log.warn("订单状态是NEW,返回给消消息队列重新投递：{}",productMessage);
                    return false;
                }
                // 已经支付
                if(ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)){
                    // 如果是已经支付,修改task状态为finish
                    productTaskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    productTaskMapper.update(productTaskDO,new QueryWrapper<ProductTaskDO>().eq("id",productMessage.getTaskID()));
                    log.info("订单已支付,修改库存锁定工作单为FINIS状态");
                    return true;
                }
            }
            // 订单不存在或者订单被取消，确认消息即可修改task状态为CANCLE，回复优惠券使用记录
            log.warn("订单不存在或者订单被取消，确认消息即可修改task状态为CANCLE，恢复商品库存,message:{}",productMessage);
            productTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            productTaskMapper.update(productTaskDO,new QueryWrapper<ProductTaskDO>().eq("id",productMessage.getTaskID()));
            // 恢复商品库存，即锁定库存的值减去当前购买的值
            productMapper.unLockProductStock(productTaskDO.getProductId(),productTaskDO.getBuyNum());
            return true;

        }
        log.warn("工作单状态不是LOCK,state={},消息体={}",productTaskDO.getLockState(),productMessage);
        return true;
    }

    private ProductVO beanProcess(ProductDO productDO) {
        ProductVO productVO = new ProductVO();
        BeanUtils.copyProperties(productDO,productVO);
        productVO.setStock(productDO.getStock()-productDO.getLockStock());
        return productVO;
    }
}